package main;

/*
 * Class offering the main functions of the library
 * @author M.T. Segarra
 * @version 0.0.1
 */

import java.util.*;

import outils.StringCalendar;

import dvdsManagement.Dvd;
import loansManagement.Loan;
import specimensManagement.Specimen;
import mediasManagement.Media;
import mediasManagement.MediaDAO;
import subscribersManagement.Subscriber;
import booksManagement.Book;
import exceptions.*;
import subscribersManagement.SubscriberDAO;

public class Library {

	/**
	 * @uml.property name="sc"
	 */
	private StringCalendar sc=new StringCalendar();

	/**
	 * @uml.property   name="loans"
	 * @uml.associationEnd   multiplicity="(0 -1)" ordering="true" inverse="library:loansManagement.Loan"
	 */
	private ArrayList loans = new ArrayList<Loan>();;

	/**
	 * @uml.property   name="medias"
	 * @uml.associationEnd   multiplicity="(0 -1)" ordering="true" inverse="library:mediasManagement.Media"
	 */
	private ArrayList<Media> medias = new ArrayList<Media>();

	/**
	 * @uml.property  name="subscribers"
	 * @uml.associationEnd  multiplicity="(0 -1)" ordering="true" inverse="library:subscribersManagement.Subscriber"
	 */
	private ArrayList subscribers = new ArrayList<Subscriber>();


	//Accessors
	public ArrayList<Media> getMedias() {
		return medias;
	}

	public ArrayList getLoans() {
		return loans;
	}

	public void setLoans(ArrayList loans) {
		this.loans = loans;
	}

	public ArrayList getSubscribers() {
		return subscribers;
	}

	public void setSubscribers(ArrayList subscribers) {
		this.subscribers = subscribers;
	}

	public void setMedias(ArrayList<Media> medias) {
		this.medias = medias;
	}

	/**
	 * @throws BadParametersException 
	 */
	public Boolean isAMedia(Media media) throws BadParametersException{
		
		if (media == null)
			throw new BadParametersException();
		
		// If the object is in the list,
		// it is a known media
		return medias.contains(media);
	}
	
	/**
	 * A utility method to know if a subscriber is known of the library
	 * 
	 * @param subscriber to
	 * @return false if the subscriber of the parameter is not known of the library
	 * @return true if the subscriber of the parameter is known of the library
	 */
	private boolean isASubscriber(Subscriber subscriber) throws BadParametersException, SubscriberExistsException {
		if (subscriber == null)
			throw new BadParametersException();

		if (subscriber.getNumber() == 0) return false;

		// If the object is in the list,
		// it is a known subscriber
		return this.subscribers.contains(subscriber);
	}

	/** 
	 * Adds a media
	 * @throws MediaExistsException 
	 */
	public void addMedia(Media media)	throws BadParametersException, MediaExistsException {
		if (media == null)
			throw new BadParametersException();

		// Look if the media is already in the library
		if (isAMedia(media)){
			addSpecimen(media);
		}
		else
			this.medias.add(media);
			mediasManagement.MediaDAO.add(media);
	}

	/**
	 */
	public void addSpecimen(Media media) throws BadParametersException, MediaExistsException{
		if (media == null)
			throw new BadParametersException();

		if (!((isAMedia(media))|| mediasManagement.MediaDAO.contains(media)))
			throw new MediaExistsException();

		int index = this.medias.indexOf(media);

		Specimen spec= new Specimen(this.medias.get(index));
		this.medias.get(index).addSpecimen(spec);
		mediasManagement.MediaDAO.addSpecimen(media);
	}
	
	public void removeSpecimen(Media media) throws BadParametersException, MediaExistsException{
		if (media == null)
			throw new BadParametersException();

		if (!((isAMedia(media))|| mediasManagement.MediaDAO.contains(media)))
			throw new MediaExistsException();

		int index = this.medias.indexOf(media);

		Specimen spec= new Specimen(this.medias.get(index));
		this.medias.get(index).removeSpecimen(spec);
		mediasManagement.MediaDAO.removeSpecimen(media);
	}

	public long addSubscriber(Subscriber s) throws BadParametersException, SubscriberExistsException
	{
		if (s == null)
			throw new BadParametersException();

		if (isASubscriber(s))
			throw new SubscriberExistsException();

		subscribersManagement.SubscriberDAO.add(s);
		subscribers.add(s);
		return s.getNumber();
	}

	
	
	/** 
	 * Adds a media
	 * @throws MediaExistsException 
	 */
	public void removeMedia(Media media)	throws BadParametersException, MediaExistsException {
		if (media == null)
			throw new BadParametersException();

		// Look if the media is already in the library
		if (isAMedia(media)){
			removeSpecimen(media);
		}
		else
			this.medias.remove(media);
			mediasManagement.MediaDAO.remove(media);
	}

	/**
	 * This method deletes data of a subscriber from the library
	 * @param subsNumber number of the subscriber
	 * @throws BadParametersException
	 * @throws SubscriberExistsException
	 */
	public void removeSubscriber(Subscriber subscriber) throws BadParametersException,
	SubscriberWithLoansException, SubscriberExistsException {


		// If the number is not a subscriber number
		// raise exception
		if (!isASubscriber(subscriber))
			throw new SubscriberExistsException();

		// If loans, raise exception
		if (subscriber.existingLoans())
			throw new SubscriberWithLoansException();

		// Remove the subscriber
		this.subscribers.remove(subscriber);
	}

	/**
	 * @return all medias of the library
	 */
	public List<Media> listMedias() {
		this.medias = (ArrayList<Media>) mediasManagement.MediaDAO.getContent();
		return this.medias;
	}

//	/**
//	 * @return all books of the library
//	 */
//	public List<Book> listBooks() {
//		return this.books.getContent();
//	}
//
//	/**
//	 * @return all dvds of the library
//	 */
//	public List<Dvd> listDvds() {
//		return this.dvds.getContent();
//	}

//	/**
//	 * @return all subscribers of the library
//	 */
//	public List<Subscriber> listSubscribers() {
//		this.subscribers = (ArrayList<Subscriber>) subscribersManagement.SubscriberDAO.getContent();
//		return this.subscribers;
//	}
//
//	public boolean isLent(Media media) throws MediaExistsException
//	{
//		List<Loan> specimens=(List<Loan>)SpecimenDAO.getAllByMedia(media.getId());
//		for (Loan s : specimens) {
//			if(s.getReturned()==false)
//				return true;
//		}
//		return false;
//	}

	/**
	 * Method to lend a book for a subscriber
	 * 
	 * @param book the book to be lent
	 * @param lender subscriber that whant to lend
	 * @return return date for the lent book
	 * @throws BadParametersException
	 * @throws BookExistsException
	 * @throws LentMediaException
	 * @throws SubscriberExistsException
	 * @throws SubscriberWithLoansException
	 * @throws TooManyLoansException
	 * @throws MediaExistsException 
	 */
//	public String lendBook(Book book, Subscriber lender) throws BadParametersException,
//	BookExistsException, LentMediaException, SubscriberExistsException, TooManyLoansException, MediaExistsException {
//
//		if (book == null || lender == null)
//			throw new BadParametersException();
//
//		// Check if the book exists
//		if (!isABook(book))
//			throw new BookExistsException();
//
//		// Check if the subscriber exists
//		if (!isASubscriber(lender))
//			throw new SubscriberExistsException();
//
//		// Make the loan if possible
//		if(!canBeLent(book))
//			throw new LentMediaException("Book has already been lent or reserved.");
//
//		if(!canLendBook(lender))
//			throw new LentMediaException("The subscriber can't lend or reserve more book.");
//		Loan spec = new Loan(book, lender);
//		this.loan.add(spec);
//		return spec.getDateReturn();
//	}
//
//	/**
//	 * Method to lend a dvd for a subscriber
//	 * 
//	 * @param dvd the dvd to be lent
//	 * @param lender subscriber that whant to lend
//	 * @return return date for the lent dvd
//	 * @throws BadParametersException
//	 * @throws DvdExistsException
//	 * @throws LentMediaException
//	 * @throws SubscriberExistsException
//	 * @throws SubscriberWithLoansException
//	 * @throws TooManyLoansException
//	 * @throws MediaExistsException 
//	 */
//	public String lendDvd (Dvd dvd, Subscriber lender) throws BadParametersException,
//	DvdExistsException, LentMediaException, SubscriberExistsException, TooManyLoansException, MediaExistsException {
//
//		if (dvd == null || lender == null)
//			throw new BadParametersException();
//
//		// Check if the book exists
//		if (!isADvd(dvd))
//			throw new DvdExistsException();
//
//		// Check if the subscriber exists
//		if (!isASubscriber(lender))
//			throw new SubscriberExistsException();
//
//		// Make the loan if possible
//		if(!canBeLent(dvd))
//			throw new LentMediaException("Dvd has already been lent or reserved.");
//
//		if(!canLendDvd(lender))
//			throw new LentMediaException("The subscriber can't lend or reserve more dvd.");
//		Loan spec = new Loan(dvd, lender);
//		this.loan.add(spec);
//		return spec.getDateReturn();
//	}
//
//	/**
//	 * 
//	 * @param book
//	 * @param subscriber
//	 * @return
//	 * @throws MediaExistsException 
//	 */
//	public int findBook(Media book, Subscriber subscriber) throws MediaExistsException
//	{
//		List<Loan> specimens=(List<Loan>)SpecimenDAO.getAllByMedia(book.getId());
//		for (Loan i : specimens) {
//			if(i.getSubscriber().equals(subscriber))
//				return i.getId();
//		}
//		return -1;
//	}
//
//	/**
//	 * 
//	 * @param dvd
//	 * @param subscriber
//	 * @return
//	 * @throws MediaExistsException 
//	 */
//	public int findDvd(Media dvd, Subscriber subscriber) throws MediaExistsException
//	{
//		List<Loan> specimens=(List<Loan>)SpecimenDAO.getAllByMedia(dvd.getId());
//		for (Loan i : specimens) {
//			if(i.getSubscriber().equals(subscriber))
//				return i.getId();
//		}
//		return -1;
//	}
//
//	/**
//	 * This method returns the book book 
//	 * @param book the book to be returned
//	 * @throws BookExistsException
//	 * @throws LentMediaException
//	 * @throws DvdExistsException 
//	 * @throws MediaExistsException 
//	 */
//	public void returnBook(Book book, Subscriber subscriber) throws BadParametersException, BookExistsException,
//	LentMediaException, SubscriberExistsException, DvdExistsException, MediaExistsException {
//		if (book == null || subscriber == null)
//			throw new BadParametersException();
//
//		// Check if the book exists
//		if (!isABook(book))
//			throw new BookExistsException();
//
//		// Check if the subscriber exists
//		if (!isASubscriber(subscriber))
//			throw new SubscriberExistsException();
//
//		// Get the loan from the list
//		int index = findBook(book, subscriber);
//
//		if(index==-1)
//			throw new LentMediaException("The book is not lent.");
//		else
//		{
//			Loan spec = SpecimenDAO.getById(index);
//			spec.setReturned(true);
//			this.loan.update(spec);
//		}
//	}
//
//	/**
//	 * This method returns the dvd
//	 * @param dvd the dvd to be returned
//	 * @throws DvdExistsException
//	 * @throws LentMediaException
//	 * @throws MediaExistsException 
//	 */
//	public void returnDvd(Dvd dvd, Subscriber subscriber) throws BadParametersException, DvdExistsException,
//	LentMediaException, SubscriberExistsException, MediaExistsException {
//		if (dvd == null || subscriber == null)
//			throw new BadParametersException();
//
//		// Check if the book exists
//		if (!isADvd(dvd))
//			throw new DvdExistsException();
//
//		// Check if the subscriber exists
//		if (!isASubscriber(subscriber))
//			throw new SubscriberExistsException();
//
//		// Get the loan from the list
//		int index = findDvd(dvd, subscriber);
//
//		if(index==-1)
//			throw new LentMediaException("The dvd is not lent.");
//		else
//		{
//			Loan spec = SpecimenDAO.getById(index);
//			spec.setReturned(true);
//			this.loan.update(spec);
//		}
//	}
//
//	/**
//	 * 
//	 * 
//	 * @param media
//	 * @return
//	 * @throws MediaExistsException
//	 */
//	public int mediaLeft(Media media) throws MediaExistsException
//	{
//		int i=0;
//		Calendar datetmp = new GregorianCalendar();
//		List<Loan> specimens=(List<Loan>)SpecimenDAO.getAllByMedia(media.getId());
//		for (Loan s : specimens) {
//			if((!s.getReturned()) && ((sc.stringToCalendar(s.getDateLoan()).get(Calendar.MONTH)-datetmp.get(Calendar.MONTH)==1 && sc.stringToCalendar(s.getDateLoan()).get(Calendar.DAY_OF_MONTH)<datetmp.get(Calendar.DAY_OF_MONTH))||(sc.stringToCalendar(s.getDateLoan()).get(Calendar.MONTH)-datetmp.get(Calendar.MONTH)<1)))
//				i++;
//		}
//		return media.getSpecimens()-i;
//	}
//
//	/**
//	 * 
//	 * 
//	 * @param media
//	 * @return
//	 * @throws MediaExistsException
//	 */
//	public boolean canBeLent(Media media) throws MediaExistsException
//	{
//		int i=0;
//		Calendar datetmp = new GregorianCalendar();
//		@SuppressWarnings("unchecked")
//		List<Loan> specimens=(List<Loan>)SpecimenDAO.getAllByMedia(media.getId());
//		for (Loan s : specimens) {
//			if((!s.getReturned()) && ((sc.stringToCalendar(s.getDateLoan()).get(Calendar.MONTH)-datetmp.get(Calendar.MONTH)==1 && sc.stringToCalendar(s.getDateLoan()).get(Calendar.DAY_OF_MONTH)<datetmp.get(Calendar.DAY_OF_MONTH))||(sc.stringToCalendar(s.getDateLoan()).get(Calendar.MONTH)-datetmp.get(Calendar.MONTH)<1)))
//				i++;
//		}
//		return (i!=media.getSpecimens());
//	}
//
//	/**
//	 * 
//	 * 
//	 * @param media
//	 * @param c
//	 * @return
//	 * @throws MediaExistsException
//	 */
//	public boolean canBeLent(Media media, Calendar c) throws MediaExistsException
//	{
//		int i=0;
//		Calendar datetmp = c;
//		List<Loan> specimens=(List<Loan>)SpecimenDAO.getAllByMedia(media.getId());
//		for (Loan s : specimens) {
//			if((!s.getReturned()) 
//					&& ((sc.stringToCalendar(s.getDateLoan()).get(Calendar.MONTH)-datetmp.get(Calendar.MONTH)==1 && sc.stringToCalendar(s.getDateLoan()).get(Calendar.DAY_OF_MONTH)<datetmp.get(Calendar.DAY_OF_MONTH))
//							||(sc.stringToCalendar(s.getDateLoan()).get(Calendar.MONTH)-datetmp.get(Calendar.MONTH)<1)))
//				i++;
//		}
//		if(i==media.getSpecimens())
//			return false;
//		return true;
//	}
//
//	/**
//	 * 
//	 * 
//	 * @param sub
//	 * @return
//	 * @throws MediaExistsException
//	 */
//	public boolean canLendBook(Subscriber sub) throws MediaExistsException{
//		int i=0;
//		List<Loan> specimens=(List<Loan>)SpecimenDAO.getAllBySub(sub.getNumber());
//		for (Loan s : specimens) {
//			if(s.getMedia().getType().equals("Book")&&!s.getReturned())
//				i++;
//		}
//		if(i==sub.getLoanBooks())
//			return false;
//		return true;
//	}
//
//	/**
//	 * 
//	 * 
//	 * @param sub
//	 * @return
//	 * @throws MediaExistsException
//	 */
//	public boolean canLendDvd(Subscriber sub) throws MediaExistsException{
//		int i=0;
//		List<Loan> specimens=(List<Loan>)SpecimenDAO.getAllBySub(sub.getNumber());
//		for (Loan s : specimens) {
//			if(s.getMedia().getType().equals("Dvd")&&!s.getReturned())
//				i++;
//		}
//		if(i==sub.getLoanDvds())
//			return false;
//		return true;
//	}
//
//	/**
//	 * 
//	 * 
//	 * @param sub
//	 * @return
//	 * @throws MediaExistsException
//	 */
//	public int quotaBook(Subscriber sub) throws MediaExistsException{
//		int i=0;
//		List<Loan> specimens=(List<Loan>)SpecimenDAO.getAllBySub(sub.getNumber());
//		for (Loan s : specimens) {
//			if(s.getMedia().getType().equals("Book")&&!s.getReturned())
//				i++;
//		}
//		return sub.getLoanBooks()-i;
//	}
//
//	/**
//	 * 
//	 * 
//	 * @param sub
//	 * @return
//	 * @throws MediaExistsException
//	 */
//	public int quotaDvd(Subscriber sub) throws MediaExistsException{
//		int i=0;
//		List<Loan> specimens=(List<Loan>)SpecimenDAO.getAllBySub(sub.getNumber());
//		for (Loan s : specimens) {
//			if(s.getMedia().getType().equals("Dvd")&&!s.getReturned())
//				i++;
//		}
//		return sub.getLoanBooks()-i;
//	}

}
